#include "APIPuertaCamion.h"

APIPuertaCamion::APIPuertaCamion() {
	// Obtengo todos los IPCs dado que no sé cuales voy a utilizar
	
	this->semControl = Semaphore();
	this->semControl.getSemaphore((char *) DIRECTORY, ID_SEMCONTROL, 1);
	this->shMem = ControlDataSharedMemory();
	this->shMem.getSharedMemory((char *) DIRECTORY, ID_SHMEM);
	
	this->semTruckDoor = Semaphore();
	this->semTruckDoor.getSemaphore((char *) DIRECTORY, ID_SEMTRUCKDOOR, CANT_DOORS);
	
	this->semTruck = Semaphore();
	this->semTruck.getSemaphore((char *) DIRECTORY, ID_SEMTRUCK, CANT_TRUCKS);

	// Obtención de colas para la comunicación con la puerta de la sala de Camiones
	this->truckDoorInputQueue = TruckDoorInputMessageQueue();
	this->truckDoorInputQueue.getMessageQueue((char *) DIRECTORY, ID_Q_TRUCK_DOOR_INPUT);
	this->truckDoorOutputQueue = TruckDoorOutputMessageQueue();
	this->truckDoorOutputQueue.getMessageQueue((char *) DIRECTORY, ID_Q_TRUCK_DOOR_OUTPUT);
	
	// 
	this->chargeToTruckQueue = ChargeToTruckMessageQueue();
	this->chargeToTruckQueue.getMessageQueue((char *) DIRECTORY, ID_Q_CHARGE_TO_TRUCK);
	
}

APIPuertaCamion::~APIPuertaCamion() {
}

// 
long APIPuertaCamion::recibirPersona(int nroPuerta, int *error) {
	TruckDoorInputMsg inputMsg;
	
	if (this->truckDoorInputQueue.recibirMensaje( (long) nroPuerta, &inputMsg) == -1) {
		// TODO: Actuar en función del error
		*error = ZIPC_FAILURE;
		return 0;
	}
	
	return inputMsg.idPersona;
}
	
//	
void APIPuertaCamion::reservarEspacioParaUnaPersona(int nroPuerta, long idPersona, int *error) {
	ControlData aControlData;	
	bool seLogroReservacion = false;	
	TruckDoorOutputMsg truckDoorOutputMsg;
	ChargeToTruckMsg chargeToTruckMsg;
	
	while (seLogroReservacion == false) {
		
		if (this->semControl.wait() == -1) {
			//TODO: Capturar el mensaje de error y ver que sucedió
			*error = ZIPC_FAILURE;
			return;
		}	
		this->shMem.read(&aControlData); 	
		
		#ifdef _DEBUG
		sprintf(buffer, "PuertaCamion %d: CPS: %d - CES: %d - CS: %d - CPC: %d\n", 
		nroPuerta, aControlData.cantidadDePersonas, aControlData.camionEnSala, 
		aControlData.capacidadSala, aControlData.cantidadPersonasEnCamion);
		write(fileno(stdout), buffer, strlen(buffer));
		#endif


		if (aControlData.capacidadSala > 0) {
			// Hay un camión en la sala, reservo un lugar para una persona
			aControlData.cantidadDePersonas++;
			aControlData.capacidadSala--;
			
			// Agrego a la cola del camión a la persona
			chargeToTruckMsg.mtype = aControlData.camionEnSala;
			chargeToTruckMsg.idPersona = idPersona;
			this->chargeToTruckQueue.enviarMensaje(chargeToTruckMsg);
			
			// Envío mensaje a la persona de que puede entrar
			truckDoorOutputMsg.mtype = idPersona;
			this->truckDoorOutputQueue.enviarMensaje(truckDoorOutputMsg);
			seLogroReservacion = true;
			
			sprintf(buffer, "PuertaCamion %d: Se reserva lugar para una persona\n", nroPuerta);
			write(fileno(stdout), buffer, strlen(buffer));
			// Libero la memoria compartida
			this->shMem.write(&aControlData);
			if (this->semControl.signal() == -1) {
				*error = ZIPC_FAILURE;
				return;
			}				
		}
		else if (aControlData.capacidadSala == 0) {			
			//Bloqueo a la puerta y libero la memoria compartida
			aControlData.puertaCamionBloqueada[nroPuerta-1] = true;
			this->shMem.write(&aControlData);
			
			if (this->semControl.signal() == -1) {
				*error = ZIPC_FAILURE;
				return;
			}
			
			sprintf(buffer, "PuertaCamion %d: Se bloquea al intentar hacer reserva\n", nroPuerta);
			write(fileno(stdout), buffer, strlen(buffer));
			if (this->semTruckDoor.wait(nroPuerta-1) == -1) {
				*error = ZIPC_FAILURE;
				return;
			}
			
			sprintf(buffer, "PuertaCamion %d: Es liberada\n", nroPuerta);
			write(fileno(stdout), buffer, strlen(buffer));
			continue;
		}	
	}	
}
	
